home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / collide.c < prev    next >
C/C++ Source or Header  |  1998-08-08  |  58KB  |  1,694 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/collide.c,v $
  15.  * $Revision: 1.4 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/08/08 15:42:31 $
  18.  * 
  19.  * $Log: collide.c,v $
  20.  * Revision 1.4  1998/08/08 15:42:31  nobody
  21.  * Activated the Editior
  22.  *
  23.  * Revision 1.3  1998/04/24 14:27:01  tfrieden
  24.  * Bugfixes (alignment problems)
  25.  *
  26.  * Revision 1.2  1998/03/25 22:03:24  tfrieden
  27.  * Removed some more warnings (storage class)
  28.  *
  29.  * Revision 1.1.1.1  1998/03/03 15:12:12  nobody
  30.  * reimport after crash from backup
  31.  *
  32.  * Revision 1.1.1.1  1998/02/13  20:20:44  hfrieden
  33.  * Initial Import
  34.  */
  35.  
  36. #pragma off (unreferenced)
  37. static char rcsid[] = "$Id: collide.c,v 1.4 1998/08/08 15:42:31 nobody Exp $";
  38. #pragma on (unreferenced)
  39.  
  40. #pragma off (unreferenced)  //for all the standard-tempate rountines
  41.  
  42. #include <string.h> // for memset
  43. #include <stdlib.h>
  44. #include <stdio.h>
  45. #include <bsd/bsd.h>
  46.  
  47. #include "rle.h"
  48. #include "inferno.h"
  49. #include "game.h"
  50. #include "gr.h"
  51. #include "stdlib.h"
  52. #include "bm.h"
  53. //#include "error.h"
  54. #include "mono.h"
  55. #include "3d.h"
  56. #include "segment.h"
  57. #include "texmap.h"
  58. #include "laser.h"
  59. #include "key.h"
  60. #include "gameseg.h"
  61. #include "object.h"
  62. #include "physics.h"
  63. #include "slew.h"       
  64. #include "render.h"
  65. #include "wall.h"
  66. #include "vclip.h"
  67. #include "polyobj.h"
  68. #include "fireball.h"
  69. #include "laser.h"
  70. #include "error.h"
  71. #include "ai.h"
  72. #include "hostage.h"
  73. #include "fuelcen.h"
  74. #include "sounds.h"
  75. #include "robot.h"
  76. #include "weapon.h"
  77. #include "player.h"
  78. #include "gauges.h"
  79. #include "powerup.h"
  80. #include "network.h"
  81. #include "newmenu.h"
  82. #include "scores.h"
  83. #include "effects.h"
  84. #include "textures.h"
  85. #include "multi.h"
  86. #include "cntrlcen.h"
  87. #include "newdemo.h"
  88. #include "endlevel.h"
  89. #include "multibot.h"
  90. #include "piggy.h"
  91. #include "text.h"
  92.  
  93. #ifdef EDITOR
  94. #include "editor/editor.h"
  95. #endif
  96.  
  97. #include "collide.h"
  98.  
  99. int Ugly_robot_cheat = 0;
  100. int Ugly_robot_texture = 0;
  101.  
  102. #define STANDARD_EXPL_DELAY (f1_0/4)
  103.  
  104. //##void collide_fireball_and_wall(object *fireball,fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)  {
  105. //##    return; 
  106. //##}
  107.  
  108. //  -------------------------------------------------------------------------------------------------------------
  109. //  The only reason this routine is called (as of 10/12/94) is so Brain guys can open doors.
  110. void collide_robot_and_wall( object * robot, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
  111. {
  112.     if ((robot->id == ROBOT_BRAIN) || (robot->ctype.ai_info.behavior == AIB_RUN_FROM)) {
  113.         int wall_num = Segments[hitseg].sides[hitwall].wall_num;
  114.         if (wall_num != -1) {
  115.             if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].keys == KEY_NONE) && (Walls[wall_num].state == WALL_DOOR_CLOSED) && !(Walls[wall_num].flags & WALL_DOOR_LOCKED)) {
  116.                 mprintf((0, "Trying to open door at segment %i, side %i\n", hitseg, hitwall));
  117.                 wall_open_door(&Segments[hitseg], hitwall);
  118.             }
  119.         }
  120.     }
  121.  
  122.     return;
  123. }
  124.  
  125. //##void collide_hostage_and_wall( object * hostage, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) {
  126. //##    return;
  127. //##}
  128.  
  129. //  -------------------------------------------------------------------------------------------------------------
  130.  
  131. int apply_damage_to_clutter(object *clutter, fix damage)
  132. {
  133.     if ( clutter->flags&OF_EXPLODING) return 0;
  134.  
  135.     if (clutter->shields < 0 ) return 0;    //clutter already dead...
  136.  
  137.     clutter->shields -= damage;
  138.  
  139.     if (clutter->shields < 0) {
  140.         explode_object(clutter,0);
  141.         return 1;
  142.     } else
  143.         return 0;
  144. }
  145.  
  146.  
  147. //given the specified force, apply damage from that force to an object
  148. apply_force_damage(object *obj,fix force,object *other_obj)
  149. {
  150.     int result;
  151.     fix damage;
  152.  
  153.     if (obj->flags & (OF_EXPLODING|OF_SHOULD_BE_DEAD))
  154.         return;     //already exploding or dead
  155.  
  156.     damage = fixdiv(force,obj->mtype.phys_info.mass) / 8;
  157.  
  158. //mprintf((0,"obj %d, damage=%x\n",obj-Objects,damage));
  159.  
  160.     switch (obj->type) {
  161.  
  162.         case OBJ_ROBOT:
  163.  
  164.             if (Robot_info[obj->id].attack_type == 1) {
  165.                 if (other_obj->type == OBJ_WEAPON)
  166.                     result = apply_damage_to_robot(obj,damage/4, other_obj->ctype.laser_info.parent_num);
  167.                 else
  168.                     result = apply_damage_to_robot(obj,damage/4, other_obj-Objects);
  169.             }
  170.             else {
  171.                 if (other_obj->type == OBJ_WEAPON)
  172.                     result = apply_damage_to_robot(obj,damage/2, other_obj->ctype.laser_info.parent_num);
  173.                 else
  174.                     result = apply_damage_to_robot(obj,damage/2, other_obj-Objects);
  175.             }       
  176.  
  177.             if (result && (other_obj->ctype.laser_info.parent_signature == ConsoleObject->signature))
  178.                 add_points_to_score(Robot_info[obj->id].score_value);
  179.             break;
  180.  
  181.         case OBJ_PLAYER:
  182.  
  183.             apply_damage_to_player(obj,other_obj,damage);
  184.             break;
  185.  
  186.         case OBJ_CLUTTER:
  187.  
  188.             apply_damage_to_clutter(obj,damage);
  189.             break;
  190.  
  191.         case OBJ_CNTRLCEN:
  192.  
  193.             apply_damage_to_controlcen(obj,damage, other_obj-Objects);
  194.             break;
  195.  
  196.         case OBJ_WEAPON:
  197.  
  198.             break;      //weapons don't take damage
  199.  
  200.         default:
  201.  
  202.             Int3();
  203.  
  204.     }
  205. }
  206.  
  207. //  -----------------------------------------------------------------------------
  208. void bump_this_object(object *objp, object *other_objp, vms_vector *force, int damage_flag)
  209. {
  210.     fix force_mag;
  211.  
  212.     if (! (objp->mtype.phys_info.flags & PF_PERSISTENT))
  213.         if (objp->type == OBJ_PLAYER) {
  214.             vms_vector force2;
  215.             force2.x = force->x/4;
  216.             force2.y = force->y/4;
  217.             force2.z = force->z/4;
  218.             phys_apply_force(objp,&force2);
  219.             if (damage_flag) {
  220.                 force_mag = vm_vec_mag_quick(&force2);
  221.                 apply_force_damage(objp, force_mag, other_objp);
  222.             }
  223.         } else if ((objp->type == OBJ_ROBOT) || (objp->type == OBJ_CLUTTER) || (objp->type == OBJ_CNTRLCEN)) {
  224.             if (!Robot_info[objp->id].boss_flag) {
  225.                 vms_vector force2;
  226.                 force2.x = force->x/(4 + Difficulty_level);
  227.                 force2.y = force->y/(4 + Difficulty_level);
  228.                 force2.z = force->z/(4 + Difficulty_level);
  229.  
  230.                 phys_apply_force(objp, force);
  231.                 phys_apply_rot(objp, &force2);
  232.                 if (damage_flag) {
  233.                     force_mag = vm_vec_mag_quick(force);
  234.                     apply_force_damage(objp, force_mag, other_objp);
  235.                 }
  236.             }
  237.         }
  238. }
  239.  
  240. //  -----------------------------------------------------------------------------
  241. //deal with two objects bumping into each other.  Apply force from collision
  242. //to each robot.  The flags tells whether the objects should take damage from
  243. //the collision.
  244. void bump_two_objects(object *obj0,object *obj1,int damage_flag)
  245. {
  246.     vms_vector  dv, force;
  247.     object      *t=NULL;
  248.  
  249.     if (obj0->movement_type != MT_PHYSICS)
  250.         t=obj1;
  251.     else if (obj1->movement_type != MT_PHYSICS)
  252.         t=obj0;
  253.  
  254.     if (t) {
  255.         Assert(t->movement_type == MT_PHYSICS);
  256.         vm_vec_copy_scale(&force,&t->mtype.phys_info.velocity,-t->mtype.phys_info.mass);
  257.         phys_apply_force(t,&force);
  258.         return;
  259.     }
  260.  
  261.     vm_vec_sub(&force,&obj0->mtype.phys_info.velocity,&obj1->mtype.phys_info.velocity);
  262.     vm_vec_scale2(&force,2*fixmul(obj0->mtype.phys_info.mass,obj1->mtype.phys_info.mass),(obj0->mtype.phys_info.mass+obj1->mtype.phys_info.mass));
  263.  
  264.     bump_this_object(obj1, obj0, &force, damage_flag);
  265.     vm_vec_negate(&force);
  266.     bump_this_object(obj0, obj1, &force, damage_flag);
  267.  
  268. }
  269.  
  270. void bump_one_object(object *obj0, vms_vector *hit_dir, fix damage)
  271. {
  272.     vms_vector  hit_vec;
  273.  
  274.     hit_vec = *hit_dir;
  275.     vm_vec_scale(&hit_vec, damage);
  276.  
  277.     phys_apply_force(obj0,&hit_vec);
  278.  
  279. }
  280.  
  281. #define DAMAGE_SCALE        128 //  Was 32 before 8:55 am on Thursday, September 15, changed by MK, walls were hurting me more than robots!
  282. #define DAMAGE_THRESHOLD    (F1_0/3)
  283. #define WALL_LOUDNESS_SCALE (20)
  284.  
  285. void collide_player_and_wall( object * player, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
  286. {
  287.     fix damage;
  288.  
  289.     if (player->id != Player_num) // Execute only for local player
  290.         return;
  291.  
  292.     //  If this wall does damage, don't make *BONK* sound, we'll be making another sound.
  293.     if (TmapInfo[Segments[hitseg].sides[hitwall].tmap_num].damage > 0)
  294.         return;
  295.  
  296.     wall_hit_process( &Segments[hitseg], hitwall, 20, player->id, player );
  297.  
  298.     //  ** Damage from hitting wall **
  299.     //  If the player has less than 10% shields, don't take damage from bump
  300.     damage = hitspeed / DAMAGE_SCALE;
  301.  
  302.     if (damage >= DAMAGE_THRESHOLD) {
  303.         int volume;
  304.         volume = (hitspeed-(DAMAGE_SCALE*DAMAGE_THRESHOLD)) / WALL_LOUDNESS_SCALE ;
  305.  
  306.         create_awareness_event(player, PA_WEAPON_WALL_COLLISION);
  307.  
  308.         if ( volume > F1_0 )
  309.             volume = F1_0;
  310.         if (volume > 0 ) {
  311.             digi_link_sound_to_pos( SOUND_PLAYER_HIT_WALL, hitseg, 0, hitpt, 0, volume );
  312.             #ifdef NETWORK
  313.             if (Game_mode & GM_MULTI)
  314.                 multi_send_play_sound(SOUND_PLAYER_HIT_WALL, volume);   
  315.             #endif
  316.         }
  317.  
  318.         if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
  319.             if ( Players[Player_num].shields > f1_0*10 )
  320.                 apply_damage_to_player( player, player, damage );
  321.     }
  322.  
  323.     return;
  324. }
  325.  
  326. fix Last_volatile_scrape_sound_time = 0;
  327.  
  328. void collide_weapon_and_wall( object * weapon, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt);
  329. void collide_debris_and_wall( object * debris, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt);
  330.  
  331. //this gets called when an object is scraping along the wall
  332. scrape_object_on_wall(object *obj, short hitseg, short hitside, vms_vector * hitpt )
  333. {
  334.     switch (obj->type) {
  335.  
  336.         case OBJ_PLAYER:
  337.  
  338.             if (obj->id==Player_num) {
  339.                 fix d;
  340.                 //mprintf((0, "Scraped segment #%3i, side #%i\n", hitseg, hitside));
  341.                 if ((d=TmapInfo[Segments[hitseg].sides[hitside].tmap_num].damage) > 0) {
  342.                     vms_vector  hit_dir, rand_vec;
  343.                     fix damage = fixmul(d,FrameTime);
  344.         
  345.                     if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
  346.                         apply_damage_to_player( obj, obj, damage );
  347.         
  348.                     PALETTE_FLASH_ADD(f2i(damage*4), 0, 0); //flash red
  349.                     if ((GameTime > Last_volatile_scrape_sound_time + F1_0/4) || (GameTime < Last_volatile_scrape_sound_time)) {
  350.                         Last_volatile_scrape_sound_time = GameTime;
  351.                         digi_link_sound_to_pos( SOUND_VOLATILE_WALL_HISS,hitseg, 0, hitpt, 0, F1_0 );
  352.                         #ifdef NETWORK
  353.                         if (Game_mode & GM_MULTI)
  354.                             multi_send_play_sound(SOUND_VOLATILE_WALL_HISS, F1_0);
  355.                         #endif
  356.                     }
  357.                     #ifdef COMPACT_SEGS
  358.                     get_side_normal(&Segments[hitseg], hitside, 0, &hit_dir );  
  359.                     #else
  360.                     hit_dir = Segments[hitseg].sides[hitside].normals[0];
  361.                     #endif
  362.                     make_random_vector(&rand_vec);
  363.                     vm_vec_scale_add2(&hit_dir, &rand_vec, F1_0/8);
  364.                     vm_vec_normalize_quick(&hit_dir);
  365.                     bump_one_object(obj, &hit_dir, F1_0*8);
  366.         
  367.                     obj->mtype.phys_info.rotvel.x = (rand() - 16384)/2;
  368.                     obj->mtype.phys_info.rotvel.z = (rand() - 16384)/2;
  369.         
  370.                 } else {
  371.                     //what scrape sound
  372.                     //PLAY_SOUND( SOUND_PLAYER_SCRAPE_WALL );
  373.                 }
  374.         
  375.             }
  376.  
  377.             break;
  378.  
  379.         //these two kinds of objects below shouldn't really slide, so
  380.         //if this scrape routine gets called (which it might if the
  381.         //object (such as a fusion blob) was created already poking
  382.         //through the wall) call the collide routine.
  383.  
  384.         case OBJ_WEAPON:
  385.             collide_weapon_and_wall(obj,0,hitseg,hitside,hitpt); 
  386.             break;
  387.  
  388.         case OBJ_DEBRIS:        
  389.             collide_debris_and_wall(obj,0,hitseg,hitside,hitpt); 
  390.             break;
  391.     }
  392.  
  393. }
  394.  
  395. //if an effect is hit, and it can blow up, then blow it up
  396. //returns true if it blew up
  397. int check_effect_blowup(segment *seg,int side,vms_vector *pnt)
  398. {
  399.     int tm,ec,db;
  400.  
  401.     if ((tm=seg->sides[side].tmap_num2) != 0)
  402.         if ((ec=TmapInfo[tm&0x3fff].eclip_num)!=-1)
  403.         if ((db=Effects[ec].dest_bm_num)!=-1 && !(Effects[ec].flags&EF_ONE_SHOT)) {
  404.                 fix u,v;
  405.                 grs_bitmap *bm = &GameBitmaps[Textures[tm&0x3fff].index];
  406.                 int x,y,t;
  407.  
  408.                 PIGGY_PAGE_IN(Textures[tm&0x3fff]);
  409.  
  410.                 //this can be blown up...did we hit it?
  411.  
  412.                 find_hitpoint_uv(&u,&v,pnt,seg,side,0); //evil: always say face zero
  413.  
  414.                 x = ((unsigned) f2i(u*bm->bm_w)) % bm->bm_w;
  415.                 y = ((unsigned) f2i(v*bm->bm_h)) % bm->bm_h;
  416.  
  417.                 switch (tm&0xc000) {        //adjust for orientation of paste-on
  418.  
  419.                     case 0x0000:    break;
  420.                     case 0x4000:    t=y; y=x; x=bm->bm_w-t-1; break;
  421.                     case 0x8000:    y=bm->bm_h-y-1; x=bm->bm_w-x-1; break;
  422.                     case 0xc000:    t=x; x=y; y=bm->bm_h-t-1; break;
  423.  
  424.                 }
  425.  
  426.                 //mprintf((0,"u,v = %x,%x   x,y=%x,%x",u,v,x,y));
  427.  
  428.                 
  429.                 if (bm->bm_flags & BM_FLAG_RLE)
  430.                     bm = rle_expand_texture(bm);
  431.  
  432.                 if (bm->bm_data[y*bm->bm_w+x] != TRANSPARENCY_COLOR) {     //not trans, thus on effect
  433.                     int vc,sound_num;
  434.  
  435.                     //mprintf((0,"  HIT!\n"));
  436.  
  437.                     if (Newdemo_state == ND_STATE_RECORDING)
  438.                         newdemo_record_effect_blowup( seg-Segments, side, pnt);
  439.  
  440.                     vc = Effects[ec].dest_vclip;
  441.  
  442.                     object_create_explosion( seg-Segments, pnt, Effects[ec].dest_size, vc );
  443.  
  444.                     if ((sound_num = Vclip[vc].sound_num) != -1)
  445.                         digi_link_sound_to_pos( sound_num, seg-Segments, 0, pnt,  0, F1_0 );
  446.  
  447.                     if ((sound_num=Effects[ec].sound_num)!=-1)      //kill sound
  448.                         digi_kill_sound_linked_to_segment(seg-Segments,side,sound_num);
  449.  
  450.                     if (Effects[ec].dest_eclip!=-1 && Effects[Effects[ec].dest_eclip].segnum==-1) {
  451.                         int bm_num;
  452.                         eclip *new_ec;
  453.  
  454.                         new_ec = &Effects[Effects[ec].dest_eclip];
  455.                         bm_num = new_ec->changing_wall_texture;
  456.  
  457.                         mprintf((0,"bm_num = %d\n",bm_num));
  458.  
  459.                         new_ec->time_left = new_ec->vc.frame_time;
  460.                         new_ec->frame_count = 0;
  461.                         new_ec->segnum = seg-Segments;
  462.                         new_ec->sidenum = side;
  463.                         new_ec->flags |= EF_ONE_SHOT;
  464.                         new_ec->dest_bm_num = Effects[ec].dest_bm_num;
  465.  
  466.                         Assert(bm_num!=0 && seg->sides[side].tmap_num2!=0);
  467.                         seg->sides[side].tmap_num2 = bm_num | (tm&0xc000);      //replace with destoyed
  468.  
  469.                     }
  470.                     else {
  471.                         Assert(db!=0 && seg->sides[side].tmap_num2!=0);
  472.                         seg->sides[side].tmap_num2 = db | (tm&0xc000);      //replace with destoyed
  473.                     }
  474.  
  475.                     return 1;       //blew up!
  476.                 }
  477.                 //else
  478.                 //  mprintf((0,"\n"));
  479.  
  480.             }
  481.  
  482.     return 0;       //didn't blow up
  483. }
  484.  
  485. //these gets added to the weapon's values when the weapon hits a volitle wall
  486. #define VOLATILE_WALL_EXPL_STRENGTH i2f(10)
  487. #define VOLATILE_WALL_IMPACT_SIZE   i2f(3)
  488. #define VOLATILE_WALL_DAMAGE_FORCE  i2f(5)
  489. #define VOLATILE_WALL_DAMAGE_RADIUS i2f(30)
  490.  
  491. // int Show_seg_and_side = 0;
  492.  
  493. void collide_weapon_and_wall( object * weapon, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
  494. {
  495.     segment *seg = &Segments[hitseg];
  496.     int blew_up;
  497.     int wall_type;
  498.     int playernum;
  499.  
  500.     #ifndef NDEBUG
  501.     if (keyd_pressed[KEY_LAPOSTRO])
  502.         if (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum)
  503.             if (weapon->id < 4)
  504.                 mprintf((0, "Your laser hit at segment = %i, side = %i\n", hitseg, hitwall));
  505.     #endif
  506.  
  507.     if (weapon->mtype.phys_info.flags & PF_BOUNCE)
  508.         return;
  509.  
  510.     if ((weapon->mtype.phys_info.velocity.x == 0) && (weapon->mtype.phys_info.velocity.y == 0) && (weapon->mtype.phys_info.velocity.z == 0)) {
  511.         Int3(); //  Contact Matt: This is impossible.  A weapon with 0 velocity hit a wall, which doesn't move.
  512.         return;
  513.     }
  514.  
  515.     blew_up = check_effect_blowup(seg,hitwall,hitpt);
  516.  
  517.     //if ((seg->sides[hitwall].tmap_num2==0) && (TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_VOLATILE)) {
  518.  
  519.     if (Objects[weapon->ctype.laser_info.parent_num].type == OBJ_PLAYER)
  520.         playernum = Objects[weapon->ctype.laser_info.parent_num].id;
  521.     else
  522.         playernum = -1;     //not a player
  523.  
  524.     wall_type = wall_hit_process( seg, hitwall, weapon->shields, playernum, weapon );
  525.  
  526.     // Wall is volatile if either tmap 1 or 2 is volatile
  527.     if ((TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_VOLATILE) || (seg->sides[hitwall].tmap_num2 && (TmapInfo[seg->sides[hitwall].tmap_num2&0x3fff].flags & TMI_VOLATILE))) {
  528.         weapon_info *wi = &Weapon_info[weapon->id];
  529.  
  530.         //we've hit a volatile wall
  531.  
  532.         digi_link_sound_to_pos( SOUND_VOLATILE_WALL_HIT,hitseg, 0, hitpt, 0, F1_0 );
  533.  
  534.         object_create_badass_explosion( weapon, hitseg, hitpt, 
  535.             wi->impact_size + VOLATILE_WALL_IMPACT_SIZE,
  536.             VCLIP_VOLATILE_WALL_HIT,
  537.             wi->strength[Difficulty_level]/4+VOLATILE_WALL_EXPL_STRENGTH,   //  diminished by mk on 12/08/94, i was doing 70 damage hitting lava on lvl 1.
  538.             wi->damage_radius+VOLATILE_WALL_DAMAGE_RADIUS,
  539.             wi->strength[Difficulty_level]/2+VOLATILE_WALL_DAMAGE_FORCE,
  540.             weapon->ctype.laser_info.parent_num );
  541.  
  542.     }
  543.     else {
  544.  
  545.         //if it's not the player's weapon, or it is the player's and there
  546.         //is no wall, and no blowing up monitor, then play sound
  547.         if ((weapon->ctype.laser_info.parent_type != OBJ_PLAYER) || ((seg->sides[hitwall].wall_num == -1 || wall_type==WHP_NOT_SPECIAL) && !blew_up))
  548.             if ((Weapon_info[weapon->id].wall_hit_sound > -1 ) && (!(weapon->flags & OF_SILENT)))
  549.                 digi_link_sound_to_pos( Weapon_info[weapon->id].wall_hit_sound,weapon->segnum, 0, &weapon->pos, 0, F1_0 );
  550.         
  551.         if ( Weapon_info[weapon->id].wall_hit_vclip > -1 )  {
  552.             if ( Weapon_info[weapon->id].damage_radius )
  553.                 explode_badass_weapon(weapon);
  554.             else
  555.                 object_create_explosion( weapon->segnum, &weapon->pos, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].wall_hit_vclip );
  556.         }
  557.     }
  558.  
  559.     if ( weapon->ctype.laser_info.parent_type== OBJ_PLAYER )    {
  560.  
  561.         if (!(weapon->flags & OF_SILENT) && (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum))
  562.             create_awareness_event(weapon, PA_WEAPON_WALL_COLLISION);           // object "weapon" can attract attention to player
  563.     
  564. //      if (weapon->id != FLARE_ID) {
  565. //  We now allow flares to open doors.
  566.         {
  567.             if (weapon->id != FLARE_ID)
  568.                 weapon->flags |= OF_SHOULD_BE_DEAD;
  569.  
  570.             if (!(weapon->flags & OF_SILENT)) {
  571.                 switch (wall_type) {
  572.  
  573.                     case WHP_NOT_SPECIAL:
  574.                         //should be handled above
  575. //                      digi_link_sound_to_pos( Weapon_info[weapon->id].wall_hit_sound, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
  576.                         break;
  577.  
  578.                     case WHP_NO_KEY:
  579.                         //play special hit door sound (if/when we get it)
  580.                         digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
  581.                         break;
  582.  
  583.                     case WHP_BLASTABLE:
  584.                         //play special blastable wall sound (if/when we get it)
  585.                         digi_link_sound_to_pos( SOUND_WEAPON_HIT_BLASTABLE, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
  586.                         break;
  587.  
  588.                     case WHP_DOOR:
  589.                         //don't play anything, since door open sound will play
  590.                         break;
  591.                 }
  592.             } // else
  593.                 //mprintf((0, "Weapon %i hits wall, but has silent bit set.\n", weapon-Objects));
  594.         } // else {
  595.             //  if (weapon->lifeleft <= 0)
  596.             //  weapon->flags |= OF_SHOULD_BE_DEAD;
  597.         // }
  598.  
  599.     } else {
  600.         // This is a robot's laser
  601.         weapon->flags |= OF_SHOULD_BE_DEAD;
  602.     }
  603.  
  604.     return;
  605. }
  606.  
  607. //##void collide_camera_and_wall( object * camera, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)   {
  608. //##    return;
  609. //##}
  610.  
  611. //##void collide_powerup_and_wall( object * powerup, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) {
  612. //##    return;
  613. //##}
  614.  
  615. void collide_debris_and_wall( object * debris, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)   {   
  616.     explode_object(debris,0);
  617.     return;
  618. }
  619.  
  620. //##void collide_fireball_and_fireball( object * fireball1, object * fireball2, vms_vector *collision_point ) {
  621. //##    return; 
  622. //##}
  623.  
  624. //##void collide_fireball_and_robot( object * fireball, object * robot, vms_vector *collision_point ) {
  625. //##    return; 
  626. //##}
  627.  
  628. //##void collide_fireball_and_hostage( object * fireball, object * hostage, vms_vector *collision_point ) {
  629. //##    return; 
  630. //##}
  631.  
  632. //##void collide_fireball_and_player( object * fireball, object * player, vms_vector *collision_point ) {
  633. //##    return; 
  634. //##}
  635.  
  636. //##void collide_fireball_and_weapon( object * fireball, object * weapon, vms_vector *collision_point ) { 
  637. //##    //weapon->flags |= OF_SHOULD_BE_DEAD;
  638. //##    return; 
  639. //##}
  640.  
  641. //##void collide_fireball_and_camera( object * fireball, object * camera, vms_vector *collision_point ) { 
  642. //##    return; 
  643. //##}
  644.  
  645. //##void collide_fireball_and_powerup( object * fireball, object * powerup, vms_vector *collision_point ) { 
  646. //##    return; 
  647. //##}
  648.  
  649. //##void collide_fireball_and_debris( object * fireball, object * debris, vms_vector *collision_point ) { 
  650. //##    return; 
  651. //##}
  652.  
  653. //  -------------------------------------------------------------------------------------------------------------------
  654. void collide_robot_and_robot( object * robot1, object * robot2, vms_vector *collision_point ) { 
  655. //  mprintf((0, "Coll: [%2i %4i %4i %4i] [%2i %4i %4i %4i] at [%4i %4i %4i]", 
  656. //      robot1-Objects, f2i(robot1->pos.x), f2i(robot1->pos.y), f2i(robot1->pos.z),
  657. //      robot2-Objects, f2i(robot2->pos.x), f2i(robot2->pos.y), f2i(robot2->pos.z),
  658. //      f2i(collision_point->x), f2i(collision_point->y), f2i(collision_point->z)));
  659.  
  660.     bump_two_objects(robot1, robot2, 1);
  661.     return; 
  662. }
  663.  
  664. void collide_robot_and_controlcen( object * obj1, object * obj2, vms_vector *collision_point )
  665. {
  666.  
  667.     if (obj1->type == OBJ_ROBOT) {
  668.         vms_vector  hitvec;
  669.         vm_vec_sub(&hitvec, &obj2->pos, &obj1->pos);
  670.         vm_vec_normalize_quick(&hitvec);
  671.         bump_one_object(obj1, &hitvec, 0);
  672.     } else {
  673.         vms_vector  hitvec;
  674.         vm_vec_sub(&hitvec, &obj1->pos, &obj2->pos);
  675.         vm_vec_normalize_quick(&hitvec);
  676.         bump_one_object(obj2, &hitvec, 0);
  677.     }
  678.  
  679. }
  680.  
  681. //##void collide_robot_and_hostage( object * robot, object * hostage, vms_vector *collision_point ) { 
  682. //##    return; 
  683. //##}
  684.  
  685. void collide_robot_and_player( object * robot, object * player, vms_vector *collision_point ) { 
  686.     if (player->id == Player_num) {
  687.         create_awareness_event(player, PA_PLAYER_COLLISION);            // object robot can attract attention to player
  688.         do_ai_robot_hit_attack(robot, player, collision_point);
  689.         do_ai_robot_hit(robot, PA_WEAPON_ROBOT_COLLISION);
  690.     } 
  691. #ifdef NETWORK
  692.     else
  693.         multi_robot_request_change(robot, player->id);
  694. #endif
  695.  
  696.     digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player->segnum, 0, collision_point, 0, F1_0 );
  697.     bump_two_objects(robot, player, 1);
  698.     return; 
  699. }
  700.  
  701. // Provide a way for network message to instantly destroy the control center
  702. // without awarding points or anything.
  703.  
  704. //  if controlcen == NULL, that means don't do the explosion because the control center
  705. //  was actually in another object.
  706. void net_destroy_controlcen(object *controlcen)
  707. {
  708.     if (Fuelcen_control_center_destroyed != 1) {
  709.         int i;
  710.  
  711.         do_controlcen_destroyed_stuff(controlcen);
  712.  
  713.         if ((controlcen != NULL) && !(controlcen->flags&(OF_EXPLODING|OF_DESTROYED))) {
  714.             digi_link_sound_to_pos( SOUND_CONTROL_CENTER_DESTROYED, controlcen->segnum, 0, &controlcen->pos, 0, F1_0 );
  715.             explode_object(controlcen,0);
  716.         }
  717.     }
  718.  
  719. }
  720.  
  721. //  -----------------------------------------------------------------------------
  722. void apply_damage_to_controlcen(object *controlcen, fix damage, short who)
  723. {
  724.     int whotype;
  725.  
  726.     //  Only allow a player to damage the control center.
  727.  
  728.     if ((who < 0) || (who > Highest_object_index))
  729.         return;
  730.  
  731.     whotype = Objects[who].type;
  732.     if (whotype != OBJ_PLAYER) {
  733.         mprintf((0, "Damage to control center by object of type %i prevented by MK!\n", whotype));
  734.         return;
  735.     }
  736.  
  737.     #ifdef NETWORK
  738.     if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) && (Players[Player_num].time_level < Netgame.control_invul_time))
  739.     {
  740.         if (Objects[who].id == Player_num) {
  741.             int secs = f2i(Netgame.control_invul_time-Players[Player_num].time_level) % 60;
  742.             int mins = f2i(Netgame.control_invul_time-Players[Player_num].time_level) / 60;
  743.             HUD_init_message("%s %d:%02d.", TXT_CNTRLCEN_INVUL, mins, secs);
  744.         }
  745.         return;
  746.     }
  747.     #endif
  748.  
  749.     if (Objects[who].id == Player_num) {
  750.         Control_center_been_hit = 1;
  751.         ai_do_cloak_stuff();
  752.     }
  753.  
  754.     if ( controlcen->shields >= 0 )
  755.         controlcen->shields -= damage;
  756.  
  757.     if ( (controlcen->shields < 0) && !(controlcen->flags&(OF_EXPLODING|OF_DESTROYED)) ) {
  758.         int i;
  759.  
  760.         do_controlcen_destroyed_stuff(controlcen);
  761.  
  762.         #ifdef NETWORK
  763.         if (Game_mode & GM_MULTI) {
  764.             if (who == Players[Player_num].objnum)
  765.                 add_points_to_score(CONTROL_CEN_SCORE);
  766.             multi_send_destroy_controlcen((ushort)(controlcen-Objects), Objects[who].id );
  767.         }
  768.         #endif
  769.  
  770.         if (!(Game_mode & GM_MULTI))
  771.             add_points_to_score(CONTROL_CEN_SCORE);
  772.  
  773.         digi_link_sound_to_pos( SOUND_CONTROL_CENTER_DESTROYED, controlcen->segnum, 0, &controlcen->pos, 0, F1_0 );
  774.  
  775.         explode_object(controlcen,0);
  776.     }
  777. }
  778.  
  779. void collide_player_and_controlcen( object * controlcen, object * player, vms_vector *collision_point )
  780.     if (player->id == Player_num) {
  781.         Control_center_been_hit = 1;
  782.         ai_do_cloak_stuff();                //  In case player cloaked, make control center know where he is.
  783.     }
  784.  
  785.     digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player->segnum, 0, collision_point, 0, F1_0 );
  786.     bump_two_objects(controlcen, player, 1);
  787.  
  788.     return; 
  789. }
  790.  
  791. //  If a persistent weapon and other object is not a weapon, weaken it, else kill it.
  792. //  If both objects are weapons, weaken the weapon.
  793. void maybe_kill_weapon(object *weapon, object *other_obj)
  794. {
  795.     if (weapon->id == PROXIMITY_ID) {
  796.         weapon->flags |= OF_SHOULD_BE_DEAD;
  797.         return;
  798.     }
  799.  
  800.     if ((weapon->mtype.phys_info.flags & PF_PERSISTENT) || (other_obj->type == OBJ_WEAPON)) {
  801.         //  Weapons do a lot of damage to weapons, other objects do much less.
  802.         if (!(weapon->mtype.phys_info.flags & PF_PERSISTENT)) {
  803.             if (other_obj->type == OBJ_WEAPON)
  804.                 weapon->shields -= other_obj->shields/2;
  805.             else
  806.                 weapon->shields -= other_obj->shields/4;
  807.  
  808.             if (weapon->shields <= 0) {
  809.                 weapon->shields = 0;
  810.                 weapon->flags |= OF_SHOULD_BE_DEAD;
  811.             }
  812.         }
  813.     } else
  814.         weapon->flags |= OF_SHOULD_BE_DEAD;
  815. }
  816.  
  817. void collide_weapon_and_controlcen( object * weapon, object *controlcen, vms_vector *collision_point  )
  818. {
  819.  
  820.     if (weapon->ctype.laser_info.parent_type == OBJ_PLAYER) {
  821.         fix damage = weapon->shields;
  822.  
  823.         if (Objects[weapon->ctype.laser_info.parent_num].id == Player_num)
  824.             Control_center_been_hit = 1;
  825.  
  826.         if ( Weapon_info[weapon->id].damage_radius )
  827.             explode_badass_weapon(weapon);
  828.         else
  829.             object_create_explosion( controlcen->segnum, collision_point, ((controlcen->size/3)*3)/4, VCLIP_SMALL_EXPLOSION );
  830.  
  831.         digi_link_sound_to_pos( SOUND_CONTROL_CENTER_HIT, controlcen->segnum, 0, collision_point, 0, F1_0 );
  832.  
  833.         damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
  834.  
  835.         apply_damage_to_controlcen(controlcen, damage, weapon->ctype.laser_info.parent_num);
  836.  
  837.         maybe_kill_weapon(weapon,controlcen);
  838.     } else {    //  If robot weapon hits control center, blow it up, make it go away, but do no damage to control center.
  839.         object_create_explosion( controlcen->segnum, collision_point, ((controlcen->size/3)*3)/4, VCLIP_SMALL_EXPLOSION );
  840.         maybe_kill_weapon(weapon,controlcen);
  841.     }
  842.  
  843. }
  844.  
  845. void collide_weapon_and_clutter( object * weapon, object *clutter, vms_vector *collision_point  )   {
  846.     short exp_vclip = VCLIP_SMALL_EXPLOSION;
  847.  
  848.     if ( clutter->shields >= 0 )
  849.         clutter->shields -= weapon->shields;
  850.  
  851.     digi_link_sound_to_pos( SOUND_LASER_HIT_CLUTTER, weapon->segnum, 0, collision_point, 0, F1_0 );
  852.  
  853.     object_create_explosion( clutter->segnum, collision_point, ((clutter->size/3)*3)/4, exp_vclip );
  854.  
  855.     if ( (clutter->shields < 0) && !(clutter->flags&(OF_EXPLODING|OF_DESTROYED)))
  856.         explode_object(clutter,STANDARD_EXPL_DELAY);
  857.  
  858.     maybe_kill_weapon(weapon,clutter);
  859. }
  860.  
  861. //--mk, 121094 -- extern void spin_robot(object *robot, vms_vector *collision_point);
  862.  
  863. //  ------------------------------------------------------------------------------------------------------
  864. //  Return 1 if robot died, else return 0
  865. int apply_damage_to_robot(object *robot, fix damage, int killer_objnum)
  866. {
  867.     if ( robot->flags&OF_EXPLODING) return 0;
  868.  
  869.     if (robot->shields < 0 ) return 0;  //robot already dead...
  870.  
  871. //  if (robot->control_type == CT_REMOTE)
  872. //      return 0; // Can't damange a robot controlled by another player
  873.  
  874.     if (Robot_info[robot->id].boss_flag)
  875.         Boss_been_hit = 1;
  876.  
  877.     robot->shields -= damage;
  878.  
  879.     if (robot->shields < 0) {
  880.  
  881. #ifndef SHAREWARE
  882. #ifdef NETWORK
  883.         if (Game_mode & GM_MULTI) {
  884.             if (multi_explode_robot_sub(robot-Objects, killer_objnum))
  885.             {
  886.                 multi_send_robot_explode(robot-Objects, killer_objnum);
  887.                 return 1;
  888.             }
  889.             else
  890.                 return 0;
  891.         }
  892. #endif
  893. #endif
  894.  
  895.         Players[Player_num].num_kills_level++;
  896.         Players[Player_num].num_kills_total++;
  897.  
  898.         if (Robot_info[robot->id].boss_flag) {
  899.             start_boss_death_sequence(robot);   //do_controlcen_destroyed_stuff(NULL);
  900.         } else
  901.             explode_object(robot,STANDARD_EXPL_DELAY);
  902.         return 1;
  903.     } else
  904.         return 0;
  905. }
  906.  
  907. //  ------------------------------------------------------------------------------------------------------
  908. void collide_robot_and_weapon( object * robot, object * weapon, vms_vector *collision_point )
  909.  
  910.     if (Robot_info[robot->id].boss_flag)
  911.         Boss_hit_this_frame = 1;
  912.  
  913.     if ( Ugly_robot_cheat == 0xBADa55 ) {
  914.         robot->rtype.pobj_info.tmap_override = Ugly_robot_texture % NumTextures;
  915.     }
  916.  
  917.     //  If a persistent weapon hit robot most recently, quick abort, else we cream the same robot many times,
  918.     //  depending on frame rate.
  919.     if (weapon->mtype.phys_info.flags & PF_PERSISTENT) {
  920.         if (weapon->ctype.laser_info.last_hitobj == robot-Objects)
  921.             return;
  922.         else
  923.             weapon->ctype.laser_info.last_hitobj = robot-Objects;
  924.  
  925.         // mprintf((0, "weapon #%i with power %i hits robot #%i.\n", weapon - Objects, f2i(weapon->shields), robot - Objects));
  926.     }
  927.  
  928. //  if (weapon->ctype.laser_info.multiplier)
  929. //      mprintf((0, "Weapon #%3i hit object %3i in frame %4i: multiplier = %7.3f, power = %i\n", weapon-Objects, robot-Objects, FrameCount, f2fl(weapon->ctype.laser_info.multiplier), f2i(weapon->shields)));
  930.  
  931. //mprintf((0, "weapon #%i hits robot #%i.\n", weapon - Objects, robot - Objects));
  932.  
  933.     if (weapon->ctype.laser_info.parent_signature == robot->signature)
  934.         return;
  935.  
  936.     if ( Weapon_info[weapon->id].damage_radius )
  937.         explode_badass_weapon(weapon);
  938.  
  939.     if ( (weapon->ctype.laser_info.parent_type==OBJ_PLAYER) && !(robot->flags & OF_EXPLODING) ) {   
  940.         object *expl_obj=NULL;
  941.  
  942.         if (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum) {
  943.             create_awareness_event(weapon, PA_WEAPON_ROBOT_COLLISION);          // object "weapon" can attract attention to player
  944.             do_ai_robot_hit(robot, PA_WEAPON_ROBOT_COLLISION);
  945.         } 
  946. #ifdef NETWORK
  947.         else
  948.             multi_robot_request_change(robot, Objects[weapon->ctype.laser_info.parent_num].id);
  949. #endif
  950.  
  951. //--mk, 121094 --       spin_robot(robot, collision_point);
  952.  
  953.         if ( Robot_info[robot->id].exp1_vclip_num > -1 )
  954.             expl_obj = object_create_explosion( weapon->segnum, collision_point, (robot->size/2*3)/4, Robot_info[robot->id].exp1_vclip_num );
  955. //NOT_USED      else if ( Weapon_info[weapon->id].robot_hit_vclip > -1 )
  956. //NOT_USED          expl_obj = object_create_explosion( weapon->segnum, collision_point, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].robot_hit_vclip );
  957.  
  958.         if (expl_obj)
  959.             obj_attach(robot,expl_obj);
  960.  
  961.         if ( Robot_info[robot->id].exp1_sound_num > -1 )
  962.             digi_link_sound_to_pos( Robot_info[robot->id].exp1_sound_num, robot->segnum, 0, collision_point, 0, F1_0 );
  963.  
  964.         if (!(weapon->flags & OF_HARMLESS)) {
  965.             fix damage = weapon->shields;
  966.  
  967.             damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
  968.  
  969.             if (! apply_damage_to_robot(robot, damage, weapon->ctype.laser_info.parent_num))
  970.                 bump_two_objects(robot, weapon, 0);     //only bump if not dead. no damage from bump
  971.             else if (weapon->ctype.laser_info.parent_signature == ConsoleObject->signature)
  972.                 add_points_to_score(Robot_info[robot->id].score_value);
  973.         }
  974.  
  975.     }
  976.  
  977.     maybe_kill_weapon(weapon,robot);
  978.  
  979.     return; 
  980. }
  981.  
  982. //##void collide_robot_and_camera( object * robot, object * camera, vms_vector *collision_point ) { 
  983. //##    return; 
  984. //##}
  985.  
  986. //##void collide_robot_and_powerup( object * robot, object * powerup, vms_vector *collision_point ) { 
  987. //##    return; 
  988. //##}
  989.  
  990. //##void collide_robot_and_debris( object * robot, object * debris, vms_vector *collision_point ) { 
  991. //##    return; 
  992. //##}
  993.  
  994. //##void collide_hostage_and_hostage( object * hostage1, object * hostage2, vms_vector *collision_point ) { 
  995. //##    return; 
  996. //##}
  997.  
  998. void collide_hostage_and_player( object * hostage, object * player, vms_vector *collision_point ) { 
  999.     // Give player points, etc.
  1000.     if ( player == ConsoleObject )  {
  1001.         add_points_to_score(HOSTAGE_SCORE);
  1002.  
  1003.         // Do effect
  1004.         hostage_rescue(hostage->id);
  1005.  
  1006.         // Remove the hostage object.
  1007.         hostage->flags |= OF_SHOULD_BE_DEAD;
  1008.  
  1009.         #ifdef NETWORK  
  1010.         if (Game_mode & GM_MULTI)
  1011.             multi_send_remobj(hostage-Objects);
  1012.         #endif
  1013.     }
  1014.     return; 
  1015. }
  1016.  
  1017. //--unused-- void collide_hostage_and_weapon( object * hostage, object * weapon, vms_vector *collision_point )
  1018. //--unused-- { 
  1019. //--unused--    //  Cannot kill hostages, as per Matt's edict!
  1020. //--unused--    //  (A fine edict, but in contradiction to the milestone: "Robots attack hostages.")
  1021. //--unused--    hostage->shields -= weapon->shields/2;
  1022. //--unused-- 
  1023. //--unused--    create_awareness_event(weapon, PA_WEAPON_ROBOT_COLLISION);          // object "weapon" can attract attention to player
  1024. //--unused-- 
  1025. //--unused--    //PLAY_SOUND_3D( SOUND_HOSTAGE_KILLED, collision_point, hostage->segnum );
  1026. //--unused--    digi_link_sound_to_pos( SOUND_HOSTAGE_KILLED, hostage->segnum , 0, collision_point, 0, F1_0 );
  1027. //--unused-- 
  1028. //--unused-- 
  1029. //--unused--    if (hostage->shields <= 0) {
  1030. //--unused--        explode_object(hostage,0);
  1031. //--unused--        hostage->flags |= OF_SHOULD_BE_DEAD;
  1032. //--unused--    }
  1033. //--unused-- 
  1034. //--unused--    if ( Weapon_info[weapon->id].damage_radius )
  1035. //--unused--        explode_badass_weapon(weapon);
  1036. //--unused-- 
  1037. //--unused--    maybe_kill_weapon(weapon,hostage);
  1038. //--unused-- 
  1039. //--unused-- }
  1040.  
  1041. //##void collide_hostage_and_camera( object * hostage, object * camera, vms_vector *collision_point ) { 
  1042. //##    return; 
  1043. //##}
  1044.  
  1045. //##void collide_hostage_and_powerup( object * hostage, object * powerup, vms_vector *collision_point ) { 
  1046. //##    return; 
  1047. //##}
  1048.  
  1049. //##void collide_hostage_and_debris( object * hostage, object * debris, vms_vector *collision_point ) { 
  1050. //##    return; 
  1051. //##}
  1052.  
  1053. void collide_player_and_player( object * player1, object * player2, vms_vector *collision_point ) { 
  1054.     digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player1->segnum, 0, collision_point, 0, F1_0 );
  1055.     bump_two_objects(player1, player2, 1);
  1056.     return;
  1057. }
  1058.  
  1059. int maybe_drop_primary_weapon_egg(object *player, int weapon_flag, int powerup_num)
  1060. {
  1061.     if (Players[player->id].primary_weapon_flags & weapon_flag)
  1062.         return call_object_create_egg(player, 1, OBJ_POWERUP, powerup_num);
  1063.     else
  1064.         return -1;
  1065. }
  1066.  
  1067. void maybe_drop_secondary_weapon_egg(object *player, int weapon_flag, int powerup_num, int count)
  1068. {
  1069.     if (Players[player->id].secondary_weapon_flags & weapon_flag) {
  1070.         int i, max_count;
  1071.  
  1072.         max_count = min(count, 3);
  1073.         for (i=0; i<max_count; i++)
  1074.             call_object_create_egg(player, 1, OBJ_POWERUP, powerup_num);
  1075.     }
  1076. }
  1077.  
  1078. void drop_player_eggs(object *player)
  1079. {
  1080. //  mprintf((0, "In drop_player_eggs...\n"));
  1081.  
  1082.     if ((player->type == OBJ_PLAYER) || (player->type == OBJ_GHOST)) {
  1083.         int num_missiles = 1;
  1084.         int pnum = player->id;
  1085.         int objnum;
  1086.  
  1087.         // Seed the random number generator so in net play the eggs will always
  1088.         // drop the same way
  1089.         #ifdef NETWORK
  1090.         if (Game_mode & GM_MULTI) 
  1091.         {
  1092.             Net_create_loc = 0;
  1093.             srand(5483L);
  1094.         }
  1095.         #endif
  1096.  
  1097.         //  If the player dies and he has powerful lasers, create the powerups here.
  1098.  
  1099.         if (Players[pnum].laser_level >= 1)
  1100.             call_object_create_egg(player, (Players[pnum].laser_level), OBJ_POWERUP, POW_LASER);
  1101.  
  1102.         //  Drop quad laser if appropos
  1103.         if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
  1104.             call_object_create_egg(player, 1, OBJ_POWERUP, POW_QUAD_FIRE);
  1105.  
  1106.         if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
  1107.             call_object_create_egg(player, 1, OBJ_POWERUP, POW_CLOAK);
  1108.  
  1109.         //  Drop the primary weapons
  1110.         objnum = maybe_drop_primary_weapon_egg(player, HAS_VULCAN_FLAG, POW_VULCAN_WEAPON);
  1111.         if (objnum!=-1)
  1112.             Objects[objnum].ctype.powerup_info.count = Players[pnum].primary_ammo[VULCAN_INDEX];
  1113.  
  1114.         maybe_drop_primary_weapon_egg(player, HAS_SPREADFIRE_FLAG, POW_SPREADFIRE_WEAPON);
  1115.         maybe_drop_primary_weapon_egg(player, HAS_PLASMA_FLAG, POW_PLASMA_WEAPON);
  1116.         maybe_drop_primary_weapon_egg(player, HAS_FUSION_FLAG, POW_FUSION_WEAPON);
  1117.  
  1118.         //  Drop the secondary weapons
  1119.         //  Note, proximity weapon only comes in packets of 4.  So drop n/2, but a max of 3 (handled inside maybe_drop..)  Make sense?
  1120.         maybe_drop_secondary_weapon_egg(player, HAS_PROXIMITY_FLAG, POW_PROXIMITY_WEAPON, (Players[player->id].secondary_ammo[PROXIMITY_INDEX]+2)/4);
  1121.         maybe_drop_secondary_weapon_egg(player, HAS_SMART_FLAG, POW_SMARTBOMB_WEAPON, Players[player->id].secondary_ammo[SMART_INDEX]);
  1122.         maybe_drop_secondary_weapon_egg(player, HAS_MEGA_FLAG, POW_MEGA_WEAPON, Players[player->id].secondary_ammo[MEGA_INDEX]);
  1123.  
  1124.         num_missiles = Players[pnum].secondary_ammo[HOMING_INDEX];
  1125.         if (num_missiles > 6)
  1126.             num_missiles = 6;
  1127.         call_object_create_egg(player, num_missiles/4, OBJ_POWERUP, POW_HOMING_AMMO_4);
  1128.         call_object_create_egg(player, num_missiles%4, OBJ_POWERUP, POW_HOMING_AMMO_1);
  1129.  
  1130.         //  If player has vulcan ammo, but no vulcan cannon, drop the ammo.
  1131.         if (!(Players[player->id].primary_weapon_flags & HAS_VULCAN_FLAG)) {
  1132.             int amount = Players[player->id].primary_ammo[VULCAN_INDEX];
  1133.             if (amount > 200) {
  1134.                 mprintf((0, "Surprising amount of vulcan ammo: %i bullets.\n", amount));
  1135.                 amount = 200;
  1136.             }
  1137.             while (amount > 0) {
  1138.                 call_object_create_egg(player, 1, OBJ_POWERUP, POW_VULCAN_AMMO);
  1139.                 amount -= VULCAN_AMMO_AMOUNT;
  1140.             }
  1141.         }
  1142.  
  1143.         //  Drop the player's missiles.
  1144.         num_missiles = Players[pnum].secondary_ammo[CONCUSSION_INDEX];
  1145.         if (num_missiles > 4)
  1146.             num_missiles = 4;
  1147.  
  1148.         call_object_create_egg(player, num_missiles/4, OBJ_POWERUP, POW_MISSILE_4);
  1149.         call_object_create_egg(player, num_missiles%4, OBJ_POWERUP, POW_MISSILE_1);
  1150.  
  1151.         //  Always drop a shield and energy powerup.
  1152.         if (Game_mode & GM_MULTI) {
  1153.             call_object_create_egg(player, 1, OBJ_POWERUP, POW_SHIELD_BOOST);
  1154.             call_object_create_egg(player, 1, OBJ_POWERUP, POW_ENERGY);
  1155.         }
  1156.  
  1157. //--        //  Drop all the keys.
  1158. //--        if (Players[Player_num].flags & PLAYER_FLAGS_BLUE_KEY) {
  1159. //--            player->contains_count = 1;
  1160. //--            player->contains_type = OBJ_POWERUP;
  1161. //--            player->contains_id = POW_KEY_BLUE;
  1162. //--            object_create_egg(player);
  1163. //--        }
  1164. //--        if (Players[Player_num].flags & PLAYER_FLAGS_RED_KEY) {
  1165. //--            player->contains_count = 1;
  1166. //--            player->contains_type = OBJ_POWERUP;
  1167. //--            player->contains_id = POW_KEY_RED;
  1168. //--            object_create_egg(player);
  1169. //--        }
  1170. //--        if (Players[Player_num].flags & PLAYER_FLAGS_GOLD_KEY) {
  1171. //--            player->contains_count = 1;
  1172. //--            player->contains_type = OBJ_POWERUP;
  1173. //--            player->contains_id = POW_KEY_GOLD;
  1174. //--            object_create_egg(player);
  1175. //--        }
  1176.     }
  1177. }
  1178.  
  1179. void apply_damage_to_player(object *player, object *killer, fix damage)
  1180. {
  1181.     if (Player_is_dead)
  1182.         return;
  1183.  
  1184.     if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
  1185.         return;
  1186.  
  1187.     if (Endlevel_sequence)
  1188.         return;
  1189.  
  1190.     //for the player, the 'real' shields are maintained in the Players[]
  1191.     //array.  The shields value in the player's object are, I think, not
  1192.     //used anywhere.  This routine, however, sets the objects shields to
  1193.     //be a mirror of the value in the Player structure. 
  1194.  
  1195.     if (player->id == Player_num) {     //is this the local player?
  1196.  
  1197.         if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) {
  1198.  
  1199.             //invincible, so just do blue flash
  1200.  
  1201.             PALETTE_FLASH_ADD(0,0,f2i(damage)*4);   //flash blue
  1202.  
  1203.         } 
  1204.         else {      //take damage, do red flash
  1205.  
  1206.             Players[Player_num].shields -= damage;
  1207.  
  1208.             PALETTE_FLASH_ADD(f2i(damage)*4,-f2i(damage/2),-f2i(damage/2)); //flash red
  1209.         }
  1210.  
  1211.         if (Players[Player_num].shields < 0)    {
  1212.  
  1213.             Players[Player_num].killer_objnum = killer-Objects;
  1214.             
  1215. //          if ( killer && (killer->type == OBJ_PLAYER))
  1216. //              Players[Player_num].killer_objnum = killer-Objects;
  1217.  
  1218.             player->flags |= OF_SHOULD_BE_DEAD;
  1219.  
  1220.         }
  1221.  
  1222.         player->shields = Players[Player_num].shields;      //mirror
  1223.  
  1224.     }
  1225. }
  1226.  
  1227. void collide_player_and_weapon( object * player, object * weapon, vms_vector *collision_point )
  1228. {
  1229.     fix     damage = weapon->shields;
  1230.     object * killer=NULL;
  1231.  
  1232.     damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
  1233.  
  1234.     if (weapon->mtype.phys_info.flags & PF_PERSISTENT)
  1235.         if (weapon->ctype.laser_info.last_hitobj == player-Objects)
  1236.             return;
  1237.         else
  1238.             weapon->ctype.laser_info.last_hitobj = player-Objects;
  1239.  
  1240.     if (player->id == Player_num)
  1241.     {
  1242.         if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
  1243.         {
  1244.             digi_link_sound_to_pos( SOUND_PLAYER_GOT_HIT, player->segnum, 0, collision_point, 0, F1_0 );
  1245.             #ifdef NETWORK
  1246.             if (Game_mode & GM_MULTI)
  1247.                 multi_send_play_sound(SOUND_PLAYER_GOT_HIT, F1_0);
  1248.             #endif
  1249.         }
  1250.         else
  1251.         {
  1252.             digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, player->segnum, 0, collision_point, 0, F1_0);
  1253.             #ifdef NETWORK
  1254.             if (Game_mode & GM_MULTI)
  1255.                 multi_send_play_sound(SOUND_WEAPON_HIT_DOOR, F1_0);
  1256.             #endif
  1257.         }
  1258.     }
  1259.  
  1260.     object_create_explosion( player->segnum, collision_point, i2f(10)/2, VCLIP_PLAYER_HIT );
  1261.     if ( Weapon_info[weapon->id].damage_radius )
  1262.         explode_badass_weapon(weapon);
  1263.  
  1264.     maybe_kill_weapon(weapon,player);
  1265.  
  1266.     bump_two_objects(player, weapon, 0);    //no damage from bump
  1267.  
  1268.     if ( !Weapon_info[weapon->id].damage_radius ) {
  1269.         if ( weapon->ctype.laser_info.parent_num > -1 )
  1270.             killer = &Objects[weapon->ctype.laser_info.parent_num];
  1271.  
  1272. //      if (weapon->id == SMART_HOMING_ID)
  1273. //          damage /= 4;
  1274.  
  1275.         if (!(weapon->flags & OF_HARMLESS))
  1276.             apply_damage_to_player( player, killer, damage);
  1277.     }
  1278.  
  1279.     //  Robots become aware of you if you get hit.
  1280.     ai_do_cloak_stuff();
  1281.  
  1282.     return; 
  1283. }
  1284.  
  1285. //  Nasty robots are the ones that attack you by running into you and doing lots of damage.
  1286. void collide_player_and_nasty_robot( object * player, object * robot, vms_vector *collision_point )
  1287. {
  1288.     digi_link_sound_to_pos( Robot_info[robot->id].claw_sound, player->segnum, 0, collision_point, 0, F1_0 );
  1289.  
  1290.     object_create_explosion( player->segnum, collision_point, i2f(10)/2, VCLIP_PLAYER_HIT );
  1291.  
  1292.     bump_two_objects(player, robot, 0); //no damage from bump
  1293.  
  1294.     apply_damage_to_player( player, robot, F1_0*(Difficulty_level+1));
  1295.  
  1296.     return; 
  1297. }
  1298.  
  1299. void collide_player_and_materialization_center(object *objp)
  1300. {
  1301.     int side;
  1302.     vms_vector  exit_dir;
  1303.     segment *segp = &Segments[objp->segnum];
  1304.  
  1305.     digi_link_sound_to_pos(SOUND_PLAYER_GOT_HIT, objp->segnum, 0, &objp->pos, 0, F1_0);
  1306. //  digi_play_sample( SOUND_PLAYER_GOT_HIT, F1_0 );
  1307.  
  1308.     object_create_explosion( objp->segnum, &objp->pos, i2f(10)/2, VCLIP_PLAYER_HIT );
  1309.  
  1310.     if (objp->id != Player_num)
  1311.         return;
  1312.  
  1313.     for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
  1314.         if (WALL_IS_DOORWAY(segp, side) & WID_FLY_FLAG) {
  1315.             vms_vector  exit_point, rand_vec;
  1316.  
  1317.             compute_center_point_on_side(&exit_point, segp, side);
  1318.             vm_vec_sub(&exit_dir, &exit_point, &objp->pos);
  1319.             vm_vec_normalize_quick(&exit_dir);
  1320.             make_random_vector(&rand_vec);
  1321.             rand_vec.x /= 4;    rand_vec.y /= 4;    rand_vec.z /= 4;
  1322.             vm_vec_add2(&exit_dir, &rand_vec);
  1323.             vm_vec_normalize_quick(&exit_dir);
  1324.         }
  1325.  
  1326.     bump_one_object(objp, &exit_dir, 64*F1_0);
  1327.  
  1328.     apply_damage_to_player( objp, NULL, 4*F1_0);
  1329.  
  1330.     return; 
  1331.  
  1332. }
  1333.  
  1334. void collide_robot_and_materialization_center(object *objp)
  1335. {
  1336.     int side;
  1337.     vms_vector  exit_dir;
  1338.     segment *segp=&Segments[objp->segnum];
  1339.  
  1340.     digi_link_sound_to_pos(SOUND_ROBOT_HIT, objp->segnum, 0, &objp->pos, 0, F1_0);
  1341. //  digi_play_sample( SOUND_ROBOT_HIT, F1_0 );
  1342.  
  1343.     if ( Robot_info[objp->id].exp1_vclip_num > -1 )
  1344.         object_create_explosion( objp->segnum, &objp->pos, (objp->size/2*3)/4, Robot_info[objp->id].exp1_vclip_num );
  1345.  
  1346.     for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
  1347.         if (WALL_IS_DOORWAY(segp, side) & WID_FLY_FLAG) {
  1348.             vms_vector  exit_point;
  1349.  
  1350.             compute_center_point_on_side(&exit_point, segp, side);
  1351.             vm_vec_sub(&exit_dir, &exit_point, &objp->pos);
  1352.             vm_vec_normalize_quick(&exit_dir);
  1353.         }
  1354.  
  1355.     bump_one_object(objp, &exit_dir, 8*F1_0);
  1356.  
  1357.     apply_damage_to_robot( objp, F1_0, -1);
  1358.  
  1359.     return; 
  1360.  
  1361. }
  1362.  
  1363. //##void collide_player_and_camera( object * player, object * camera, vms_vector *collision_point ) { 
  1364. //##    return; 
  1365. //##}
  1366.  
  1367. extern int Network_got_powerup; // HACK!!!
  1368.  
  1369. void collide_player_and_powerup( object * player, object * powerup, vms_vector *collision_point ) { 
  1370.     if (!Endlevel_sequence && !Player_is_dead && (player->id == Player_num )) {
  1371.         int powerup_used;
  1372.  
  1373.         powerup_used = do_powerup(powerup);
  1374.         
  1375.         if (powerup_used)   {
  1376.             powerup->flags |= OF_SHOULD_BE_DEAD;
  1377.             #ifdef NETWORK
  1378.             if (Game_mode & GM_MULTI)
  1379.                 multi_send_remobj(powerup-Objects);
  1380.             #endif
  1381.         }
  1382.     }
  1383. #ifndef SHAREWARE
  1384.     else if ((Game_mode & GM_MULTI_COOP) && (player->id != Player_num))
  1385.     {
  1386.         switch (powerup->id) {
  1387.             case POW_KEY_BLUE:  
  1388.                 Players[player->id].flags |= PLAYER_FLAGS_BLUE_KEY;
  1389.                 break;
  1390.             case POW_KEY_RED:   
  1391.                 Players[player->id].flags |= PLAYER_FLAGS_RED_KEY;
  1392.                 break;
  1393.             case POW_KEY_GOLD:  
  1394.                 Players[player->id].flags |= PLAYER_FLAGS_GOLD_KEY;
  1395.                 break;
  1396.             default:
  1397.                 break;
  1398.         }
  1399.     }
  1400. #endif
  1401.     return; 
  1402. }
  1403.  
  1404. //##void collide_player_and_debris( object * player, object * debris, vms_vector *collision_point ) { 
  1405. //##    return; 
  1406. //##}
  1407.  
  1408. void collide_player_and_clutter( object * player, object * clutter, vms_vector *collision_point ) { 
  1409.     digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player->segnum, 0, collision_point, 0, F1_0 );
  1410.     bump_two_objects(clutter, player, 1);
  1411.     return; 
  1412. }
  1413.  
  1414. //  See if weapon1 creates a badass explosion.  If so, create the explosion
  1415. //  Return true if weapon does proximity (as opposed to only contact) damage when it explodes.
  1416. int maybe_detonate_weapon(object *weapon1, object *weapon2, vms_vector *collision_point)
  1417. {
  1418.     if ( Weapon_info[weapon1->id].damage_radius ) {
  1419.         fix dist;
  1420.  
  1421.         dist = vm_vec_dist_quick(&weapon1->pos, &weapon2->pos);
  1422.         if (dist < F1_0*5) {
  1423.             maybe_kill_weapon(weapon1,weapon2);
  1424.             if (weapon1->flags & OF_SHOULD_BE_DEAD) {
  1425.                 explode_badass_weapon(weapon1);
  1426.                 digi_link_sound_to_pos( Weapon_info[weapon1->id].robot_hit_sound, weapon1->segnum , 0, collision_point, 0, F1_0 );
  1427.             }
  1428.             return 1;
  1429.         } else {
  1430.             weapon1->lifeleft = min(dist/64, F1_0);
  1431.             return 1;
  1432.         }
  1433.     } else
  1434.         return 0;
  1435. }
  1436.  
  1437. void collide_weapon_and_weapon( object * weapon1, object * weapon2, vms_vector *collision_point )
  1438.     if ((Weapon_info[weapon1->id].destroyable) || (Weapon_info[weapon2->id].destroyable)) {
  1439.  
  1440.         //  Bug reported by Adam Q. Pletcher on September 9, 1994, smart bomb homing missiles were toasting each other.
  1441.         if ((weapon1->id == weapon2->id) && (weapon1->ctype.laser_info.parent_num == weapon2->ctype.laser_info.parent_num))
  1442.             return;
  1443.  
  1444.         if (Weapon_info[weapon1->id].destroyable)
  1445.             if (maybe_detonate_weapon(weapon1, weapon2, collision_point))
  1446.                 maybe_kill_weapon(weapon2,weapon1);
  1447.  
  1448.         if (Weapon_info[weapon2->id].destroyable)
  1449.             if (maybe_detonate_weapon(weapon2, weapon1, collision_point))
  1450.                 maybe_kill_weapon(weapon1,weapon2);
  1451.  
  1452.     }
  1453.  
  1454. }
  1455.  
  1456. //##void collide_weapon_and_camera( object * weapon, object * camera, vms_vector *collision_point ) { 
  1457. //##    return; 
  1458. //##}
  1459.  
  1460. //##void collide_weapon_and_powerup( object * weapon, object * powerup, vms_vector *collision_point ) { 
  1461. //##    return; 
  1462. //##}
  1463.  
  1464. void collide_weapon_and_debris( object * weapon, object * debris, vms_vector *collision_point ) { 
  1465.  
  1466.     if ( (weapon->ctype.laser_info.parent_type==OBJ_PLAYER) && !(debris->flags & OF_EXPLODING) )    {   
  1467.         digi_link_sound_to_pos( SOUND_ROBOT_HIT, weapon->segnum , 0, collision_point, 0, F1_0 );
  1468.  
  1469.         explode_object(debris,0);
  1470.         if ( Weapon_info[weapon->id].damage_radius )
  1471.             explode_badass_weapon(weapon);
  1472.         maybe_kill_weapon(weapon,debris);
  1473.         weapon->flags |= OF_SHOULD_BE_DEAD;
  1474.     }
  1475.     return; 
  1476. }
  1477.  
  1478. //##void collide_camera_and_camera( object * camera1, object * camera2, vms_vector *collision_point ) { 
  1479. //##    return; 
  1480. //##}
  1481.  
  1482. //##void collide_camera_and_powerup( object * camera, object * powerup, vms_vector *collision_point ) { 
  1483. //##    return; 
  1484. //##}
  1485.  
  1486. //##void collide_camera_and_debris( object * camera, object * debris, vms_vector *collision_point ) { 
  1487. //##    return; 
  1488. //##}
  1489.  
  1490. //##void collide_powerup_and_powerup( object * powerup1, object * powerup2, vms_vector *collision_point ) { 
  1491. //##    return; 
  1492. //##}
  1493.  
  1494. //##void collide_powerup_and_debris( object * powerup, object * debris, vms_vector *collision_point ) { 
  1495. //##    return; 
  1496. //##}
  1497.  
  1498. //##void collide_debris_and_debris( object * debris1, object * debris2, vms_vector *collision_point ) { 
  1499. //##    return; 
  1500. //##}
  1501.  
  1502. #pragma on (unreferenced)                   // No warnings for unreferenced vars, eh?
  1503.  
  1504. #define COLLISION_OF(a,b) (((a)<<8) + (b))
  1505.  
  1506. #define DO_COLLISION(type1,type2,collision_function)                        \
  1507.     case COLLISION_OF( (type1), (type2) ):                                      \
  1508.         (collision_function)( (A), (B), collision_point );              \
  1509.         break;                                                                          \
  1510.     case COLLISION_OF( (type2), (type1) ):                                      \
  1511.         (collision_function)( (B), (A), collision_point );                  \
  1512.         break;
  1513.  
  1514. #define DO_SAME_COLLISION(type1,type2,collision_function)               \
  1515.     case COLLISION_OF( (type1), (type1) ):                                      \
  1516.         (collision_function)( (A), (B), collision_point );              \
  1517.         break;                                                                          
  1518.  
  1519. //these next two macros define a case that does nothing
  1520. #define NO_COLLISION(type1,type2,collision_function)                        \
  1521.     case COLLISION_OF( (type1), (type2) ):                                      \
  1522.         break;                                                                          \
  1523.     case COLLISION_OF( (type2), (type1) ):                                      \
  1524.         break;
  1525.  
  1526. #define NO_SAME_COLLISION(type1,type2,collision_function)               \
  1527.     case COLLISION_OF( (type1), (type1) ):                                      \
  1528.         break;                                                                          
  1529.  
  1530. #define IGNORE_COLLISION(type1,type2,collision_function)                    \
  1531.     case COLLISION_OF( (type1), (type2) ):                                      \
  1532.         break;                                                                          \
  1533.     case COLLISION_OF( (type2), (type1) ):                                      \
  1534.         break;
  1535.  
  1536. #define ERROR_COLLISION(type1,type2,collision_function)                 \
  1537.     case COLLISION_OF( (type1), (type2) ):                                      \
  1538.         Error( "Error in collision type!" );                                    \
  1539.         break;                                                                          \
  1540.     case COLLISION_OF( (type2), (type1) ):                                      \
  1541.         Error( "Error in collision type!" );                                    \
  1542.         break;
  1543.  
  1544. void collide_two_objects( object * A, object * B, vms_vector *collision_point )
  1545. {
  1546.     int collision_type; 
  1547.         
  1548.     collision_type = COLLISION_OF(A->type,B->type);
  1549.  
  1550.     //mprintf( (0, "Object %d of type %d collided with object %d of type %d\n", A-Objects,A->type, B-Objects, B->type ));
  1551.  
  1552.     switch( collision_type )    {
  1553.     NO_SAME_COLLISION( OBJ_FIREBALL, OBJ_FIREBALL,   collide_fireball_and_fireball )
  1554.     DO_SAME_COLLISION( OBJ_ROBOT, OBJ_ROBOT, collide_robot_and_robot )
  1555.     NO_SAME_COLLISION( OBJ_HOSTAGE, OBJ_HOSTAGE,  collide_hostage_and_hostage )
  1556.     DO_SAME_COLLISION( OBJ_PLAYER, OBJ_PLAYER,  collide_player_and_player )
  1557.     DO_SAME_COLLISION( OBJ_WEAPON, OBJ_WEAPON,  collide_weapon_and_weapon )
  1558.     NO_SAME_COLLISION( OBJ_CAMERA, OBJ_CAMERA, collide_camera_and_camera )
  1559.     NO_SAME_COLLISION( OBJ_POWERUP, OBJ_POWERUP,  collide_powerup_and_powerup )
  1560.     NO_SAME_COLLISION( OBJ_DEBRIS, OBJ_DEBRIS,  collide_debris_and_debris )
  1561.     NO_COLLISION( OBJ_FIREBALL, OBJ_ROBOT,   collide_fireball_and_robot )
  1562.     NO_COLLISION( OBJ_FIREBALL, OBJ_HOSTAGE, collide_fireball_and_hostage )
  1563.     NO_COLLISION( OBJ_FIREBALL, OBJ_PLAYER,  collide_fireball_and_player )
  1564.     NO_COLLISION( OBJ_FIREBALL, OBJ_WEAPON,  collide_fireball_and_weapon )
  1565.     NO_COLLISION( OBJ_FIREBALL, OBJ_CAMERA,  collide_fireball_and_camera )
  1566.     NO_COLLISION( OBJ_FIREBALL, OBJ_POWERUP, collide_fireball_and_powerup )
  1567.     NO_COLLISION( OBJ_FIREBALL, OBJ_DEBRIS,  collide_fireball_and_debris )
  1568.     NO_COLLISION( OBJ_ROBOT, OBJ_HOSTAGE, collide_robot_and_hostage )
  1569.     DO_COLLISION( OBJ_ROBOT, OBJ_PLAYER,  collide_robot_and_player )
  1570.     DO_COLLISION( OBJ_ROBOT, OBJ_WEAPON,  collide_robot_and_weapon )
  1571.     NO_COLLISION( OBJ_ROBOT, OBJ_CAMERA,  collide_robot_and_camera )
  1572.     NO_COLLISION( OBJ_ROBOT, OBJ_POWERUP, collide_robot_and_powerup )
  1573.     NO_COLLISION( OBJ_ROBOT, OBJ_DEBRIS,  collide_robot_and_debris )
  1574.     DO_COLLISION( OBJ_HOSTAGE, OBJ_PLAYER,  collide_hostage_and_player )
  1575.     NO_COLLISION( OBJ_HOSTAGE, OBJ_WEAPON,  collide_hostage_and_weapon )
  1576.     NO_COLLISION( OBJ_HOSTAGE, OBJ_CAMERA,  collide_hostage_and_camera )
  1577.     NO_COLLISION( OBJ_HOSTAGE, OBJ_POWERUP, collide_hostage_and_powerup )
  1578.     NO_COLLISION( OBJ_HOSTAGE, OBJ_DEBRIS,  collide_hostage_and_debris )
  1579.     DO_COLLISION( OBJ_PLAYER, OBJ_WEAPON,  collide_player_and_weapon )
  1580.     NO_COLLISION( OBJ_PLAYER, OBJ_CAMERA,  collide_player_and_camera )
  1581.     DO_COLLISION( OBJ_PLAYER, OBJ_POWERUP, collide_player_and_powerup )
  1582.     NO_COLLISION( OBJ_PLAYER, OBJ_DEBRIS,  collide_player_and_debris )
  1583.     DO_COLLISION( OBJ_PLAYER, OBJ_CNTRLCEN, collide_player_and_controlcen )
  1584.     DO_COLLISION( OBJ_PLAYER, OBJ_CLUTTER, collide_player_and_clutter )
  1585.     NO_COLLISION( OBJ_WEAPON, OBJ_CAMERA,  collide_weapon_and_camera )
  1586.     NO_COLLISION( OBJ_WEAPON, OBJ_POWERUP, collide_weapon_and_powerup )
  1587.     DO_COLLISION( OBJ_WEAPON, OBJ_DEBRIS,  collide_weapon_and_debris )
  1588.     NO_COLLISION( OBJ_CAMERA, OBJ_POWERUP, collide_camera_and_powerup )
  1589.     NO_COLLISION( OBJ_CAMERA, OBJ_DEBRIS,  collide_camera_and_debris )
  1590.     NO_COLLISION( OBJ_POWERUP, OBJ_DEBRIS,  collide_powerup_and_debris )
  1591.     DO_COLLISION( OBJ_WEAPON, OBJ_CNTRLCEN, collide_weapon_and_controlcen )
  1592.     DO_COLLISION( OBJ_ROBOT, OBJ_CNTRLCEN, collide_robot_and_controlcen )
  1593.     DO_COLLISION( OBJ_WEAPON, OBJ_CLUTTER, collide_weapon_and_clutter )
  1594.     default:
  1595.         Int3(); //Error( "Unhandled collision_type in collide.c!\n" );
  1596.     }
  1597. }
  1598.  
  1599. #define ENABLE_COLLISION(type1,type2)                   \
  1600.     CollisionResult[type1][type2] = RESULT_CHECK;   \
  1601.     CollisionResult[type2][type1] = RESULT_CHECK;
  1602.  
  1603. #define DISABLE_COLLISION(type1,type2)                  \
  1604.     CollisionResult[type1][type2] = RESULT_NOTHING; \
  1605.     CollisionResult[type2][type1] = RESULT_NOTHING;
  1606.  
  1607. void collide_init() {
  1608.     int i, j;
  1609.  
  1610.     for (i=0; i < MAX_OBJECT_TYPES; i++ )
  1611.         for (j=0; j < MAX_OBJECT_TYPES; j++ )
  1612.             CollisionResult[i][j] = RESULT_NOTHING;
  1613.  
  1614.     ENABLE_COLLISION( OBJ_WALL, OBJ_ROBOT );
  1615.     ENABLE_COLLISION( OBJ_WALL, OBJ_WEAPON );
  1616.     ENABLE_COLLISION( OBJ_WALL, OBJ_PLAYER  );
  1617.     DISABLE_COLLISION( OBJ_FIREBALL, OBJ_FIREBALL );
  1618.  
  1619.     ENABLE_COLLISION( OBJ_ROBOT, OBJ_ROBOT );
  1620. //  DISABLE_COLLISION( OBJ_ROBOT, OBJ_ROBOT );  //  ALERT: WARNING: HACK: MK = RESPONSIBLE! TESTING!!
  1621.  
  1622.     DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_HOSTAGE );
  1623.     ENABLE_COLLISION( OBJ_PLAYER, OBJ_PLAYER );
  1624.     ENABLE_COLLISION( OBJ_WEAPON, OBJ_WEAPON );
  1625.     DISABLE_COLLISION( OBJ_CAMERA, OBJ_CAMERA );
  1626.     DISABLE_COLLISION( OBJ_POWERUP, OBJ_POWERUP );
  1627.     DISABLE_COLLISION( OBJ_DEBRIS, OBJ_DEBRIS );
  1628.     DISABLE_COLLISION( OBJ_FIREBALL, OBJ_ROBOT );
  1629.     DISABLE_COLLISION( OBJ_FIREBALL, OBJ_HOSTAGE );
  1630.     DISABLE_COLLISION( OBJ_FIREBALL, OBJ_PLAYER );
  1631.     DISABLE_COLLISION( OBJ_FIREBALL, OBJ_WEAPON );
  1632.     DISABLE_COLLISION( OBJ_FIREBALL, OBJ_CAMERA );
  1633.     DISABLE_COLLISION( OBJ_FIREBALL, OBJ_POWERUP );
  1634.     DISABLE_COLLISION( OBJ_FIREBALL, OBJ_DEBRIS );
  1635.     DISABLE_COLLISION( OBJ_ROBOT, OBJ_HOSTAGE );
  1636.     ENABLE_COLLISION( OBJ_ROBOT, OBJ_PLAYER );
  1637.     ENABLE_COLLISION( OBJ_ROBOT, OBJ_WEAPON );
  1638.     DISABLE_COLLISION( OBJ_ROBOT, OBJ_CAMERA );
  1639.     DISABLE_COLLISION( OBJ_ROBOT, OBJ_POWERUP );
  1640.     DISABLE_COLLISION( OBJ_ROBOT, OBJ_DEBRIS );
  1641.     ENABLE_COLLISION( OBJ_HOSTAGE, OBJ_PLAYER );
  1642.     ENABLE_COLLISION( OBJ_HOSTAGE, OBJ_WEAPON );
  1643.     DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_CAMERA );
  1644.     DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_POWERUP );
  1645.     DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_DEBRIS );
  1646.     ENABLE_COLLISION( OBJ_PLAYER, OBJ_WEAPON );
  1647.     DISABLE_COLLISION( OBJ_PLAYER, OBJ_CAMERA );
  1648.     ENABLE_COLLISION( OBJ_PLAYER, OBJ_POWERUP );
  1649.     DISABLE_COLLISION( OBJ_PLAYER, OBJ_DEBRIS );
  1650.     DISABLE_COLLISION( OBJ_WEAPON, OBJ_CAMERA );
  1651.     DISABLE_COLLISION( OBJ_WEAPON, OBJ_POWERUP );
  1652.     ENABLE_COLLISION( OBJ_WEAPON, OBJ_DEBRIS );
  1653.     DISABLE_COLLISION( OBJ_CAMERA, OBJ_POWERUP );
  1654.     DISABLE_COLLISION( OBJ_CAMERA, OBJ_DEBRIS );
  1655.     DISABLE_COLLISION( OBJ_POWERUP, OBJ_DEBRIS );
  1656.     ENABLE_COLLISION( OBJ_POWERUP, OBJ_WALL );
  1657.     ENABLE_COLLISION( OBJ_WEAPON, OBJ_CNTRLCEN )
  1658.     ENABLE_COLLISION( OBJ_WEAPON, OBJ_CLUTTER )
  1659.     ENABLE_COLLISION( OBJ_PLAYER, OBJ_CNTRLCEN )
  1660.     ENABLE_COLLISION( OBJ_ROBOT, OBJ_CNTRLCEN )
  1661.     ENABLE_COLLISION( OBJ_PLAYER, OBJ_CLUTTER )
  1662.     
  1663.  
  1664. }
  1665.  
  1666. void collide_object_with_wall( object * A, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt )
  1667. {
  1668.  
  1669.     switch( A->type )   {
  1670.     case OBJ_NONE:
  1671.         Error( "A object of type NONE hit a wall!\n");
  1672.         break;
  1673.     case OBJ_PLAYER:        collide_player_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
  1674.     case OBJ_WEAPON:        collide_weapon_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
  1675.     case OBJ_DEBRIS:        collide_debris_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
  1676.  
  1677.     case OBJ_FIREBALL:  break;      //collide_fireball_and_wall(A,hitspeed,hitseg,hitwall,hitpt); 
  1678.     case OBJ_ROBOT:     collide_robot_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
  1679.     case OBJ_HOSTAGE:       break;      //collide_hostage_and_wall(A,hitspeed,hitseg,hitwall,hitpt); 
  1680.     case OBJ_CAMERA:        break;      //collide_camera_and_wall(A,hitspeed,hitseg,hitwall,hitpt); 
  1681.     case OBJ_POWERUP:       break;      //collide_powerup_and_wall(A,hitspeed,hitseg,hitwall,hitpt); 
  1682.     case OBJ_GHOST:     break;  //do nothing
  1683.  
  1684.     default:
  1685.         Error( "Unhandled object type hit wall in collide.c\n" );
  1686.     }
  1687. }
  1688.  
  1689.  
  1690.  
  1691.